<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        /* 表单和遮罩层 */
        .mask,
        body>form {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
        }

        .mask {
            background-color: rgba(0, 0, 0, .3);
        }

        /* 动画渐显 */
        .show {
            visibility: visible;
            opacity: 1;
            transition: all .5s;
        }

        .hide {
            visibility: hidden;
            opacity: 0;
        }

        body>form {
            width: 300px;
            height: 220px;
            margin: auto;
            padding: 10px;
            background-color: #f2f2f2;
        }

        body>form p {
            padding: 10px;
        }

        button,
        input,
        select {
            padding: 2px 10px;
            vertical-align: middle;
        }

        body>form #close {
            position: absolute;
            right: 10px;
            cursor: pointer;
        }

        body>form label {
            display: inline-block;
            width: 50px;
        }

        /* 表格 */
        table {
            width: 600px;
            margin: 50px auto;
            border-collapse: collapse;
        }

        table caption {
            margin: 10px 0;
            text-align: left;
        }

        table caption h3 {
            text-align: center;
            margin: 10px 0;
        }

        table caption .left {
            float: left;
        }

        table caption .right {
            float: right;
        }

        table,
        table th,
        table td {
            padding: 10px;
            border: 1px solid #ccc;
        }

        /* 分页 */
        #pager {
            text-align: center;
        }

        #pager button {
            cursor: pointer;
        }

        #pager span {
            margin-left: 15px;
        }
    </style>
</head>

<body>
    <!-- 遮罩层 -->
    <div id="mask"></div>
    <!-- 表单 -->
    <form action="" id="form" class="hide" data-action="add">
        <span id="close">&times;</span>
        <h3>添加</h3>
        <p>
            <label for="stu_name">姓名：</label>
            <input type="text" size="5" name="stu_name" id="stu_name">
        </p>
        <p>
            <label for="stu_age">年龄：</label>
            <select name="stu_age" id="stu_age">
                <option value="15" selected>15</option>
                <option value="16">16</option>
                <option value="17">17</option>
                <option value="18">18</option>
                <option value="19">19</option>
                <option value="20">20</option>
            </select>
        </p>
        <p>
            <label for="">性别：</label>
            <input type="radio" name="stu_sex" value="男" checked> 男
            <input type="radio" name="stu_sex" value="女"> 女
        </p>
        <p>
            <label for=""></label><button>保存</button>
        </p>
    </form>

    <!-- 数据表格 -->
    <table>
        <caption>
            <h3>学生表</h3>
            <form action="" id="searchForm">
                <p class="left">
                    <button type="button" id="delAll">批量软删</button>
                    <button type="button" id="pop">添加</button>
                </p>
                <p class="right">
                    <input type="text" size="5" name="stu_name" placeholder="姓名">
                    <span>年龄:</span>
                    <select name="start">
                        <option value="" selected>&mdash;</option>
                        <option value="15">15</option>
                        <option value="16">16</option>
                        <option value="17">17</option>
                        <option value="18">18</option>
                        <option value="19">19</option>
                        <option value="20">20</option>
                    </select>
                    <span>-</span>
                    <select name="end">
                        <option value="" selected>&mdash;</option>
                        <option value="15">15</option>
                        <option value="16">16</option>
                        <option value="17">17</option>
                        <option value="18">18</option>
                        <option value="19">19</option>
                        <option value="20">20</option>
                    </select>
                    <select name="stu_sex">
                        <option value="" selected>性别</option>
                        <option value="男">男</option>
                        <option value="女">女</option>
                    </select>
                    <button>搜索</button>
                </p>
            </form>
        </caption>
        <thead>
            <tr>
                <th><input type="checkbox" id="chkAll"></th>
                <th>ID</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>状态</th>
                <th>操作</th>
            </tr>
        </thead>
        <!-- 数据渲染 -->
        <tbody>
        </tbody>
        <!-- 分页 -->
        <tfoot>
            <tr>
                <td colspan="7" id="pager"></td>
            </tr>
        </tfoot>
    </table>
</body>
<!-- 引入axios 和 模板引擎 -->
<script src="https://fastly.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://fastly.jsdelivr.net/npm/art-template@4.13.2/lib/template-web.js"></script>
<!-- 数据模板 -->
<script type="text/html" id="tpl">
    {{each data}}
    <tr>
        <td><input type="checkbox" class="chk" data-id="{{$value.stu_id}}"></td>
        <td>{{$value.stu_id}}</td>
        <td>{{$value.stu_name}}</td>
        <td>{{$value.stu_age}}</td>
        <td>{{$value.stu_sex}}</td>
        <td>{{$value.status ? '已软删' : '正常'}}</td>
        <td><a href="javascript:;" data-id="{{$value.stu_id}}" data-action="edit">编辑</a> | <a href="javascript:;" data-id="{{$value.stu_id}}" data-action="del">删除</a> | <a href="javascript:;" data-id="{{$value.stu_id}}" data-action="restore">还原</a></td>
    </tr>
    {{/each}}
</script>
<!-- 分页模板 -->
<script type="text/html" id="tpl-pager">
    {{each pages}}
        {{if $value == 1}}
            <button data-page={{page - 1 < 1 ? 1 : page - 1}} title="上一页" {{1 == page ? ' disabled' : ''}}>上一页</button>
        {{/if}}
        <button data-page={{$value}} title="第{{$value}}页" {{$value == page ? ' disabled' : ''}}>{{$value}}</button>
        {{if $value == size}}
            <button data-page={{page + 1 > size ? size : page + 1}} title="下一页" {{size == page ? ' disabled' : ''}}>下一页</button>
        {{/if}}
    {{/each}}
    <span>
        每页显示
        <select class="per_page">
            <option value="2" {{if per_page == 2}} selected{{/if}}>2</option>
            <option value="3" {{if per_page == 3}} selected{{/if}}>3</option>
            <option value="4" {{if per_page == 4}} selected{{/if}}>4</option>
            <option value="5" {{if per_page == 5}} selected{{/if}}>5</option>
        </select>
        条
    </span>
</script>

<script>
    // 获取元素
    const tbody = document.querySelector('tbody');
    const pager = document.querySelector('#pager');
    const form = document.forms.namedItem('form');
    const close = document.querySelector('form #close');
    const pop = document.querySelector('#pop');
    const mask = document.querySelector('#mask');

    const searchForm = document.forms.namedItem('searchForm');
    const delAll = document.querySelector('#delAll');

    // 初始化并执行
    let per_page = 3;
    const init = (options = {}) => {
        let page = options.page || 1;
        let search = options.search || {};
        axios.get(`http://127.0.0.1:8080/api/user`, {
            params: {
                page, search, per_page
            }
        }).then(res => {
            let { data } = res;
            if (data.status) return alert(data.msg);
            // 渲染数据
            tbody.innerHTML = template('tpl', data);
            // 渲染分页
            let pages = [];
            let size = Math.ceil(data.count / per_page);
            for (let i = 1; i <= size; i++) pages.push(i);
            let pagers = { page, size, pages, per_page };
            pager.innerHTML = template('tpl-pager', pagers);
        });
    }
    init();

    // 搜索查询
    let search = {}
    searchForm.onsubmit = function (e) {
        // 禁止默认提交
        e.preventDefault();
        let data = e.target;
        if (data.stu_name.value) search.stu_name = data.stu_name.value;
        if (data.start.value) search.start = data.start.value;
        if (data.end.value) search.end = data.end.value;
        if (data.stu_sex.value) search.stu_sex = data.stu_sex.value;
        // 分页搜索
        init({ search })
    }

    // 监听分页
    let page = 1;
    pager.addEventListener('click', e => {
        if (e.target.nodeName === 'BUTTON') {
            page = e.target.dataset.page;
            init({ page, search });
        }
    });

    // 监听分页数量改变
    pager.addEventListener('change', e => {
        if (e.target.nodeName === 'SELECT' && e.target.className === 'per_page') {
            per_page = e.target.value;
            init({ page: 1, search});
        }
    });

    // 显示表单
    const show = () => {
        mask.classList.add('mask');
        form.classList.remove('hide');
        form.classList.add('show');
    }
    const hide = () => {
        mask.classList.remove('mask');
        form.classList.remove('show');
        form.classList.add('hide');
        form.reset();
    }
    pop.onclick = () => {
        form.querySelector('h3').innerHTML = '添加';
        form.dataset.action = 'add';
        form.removeAttribute('data-id');
        show();
    }
    close.onclick = hide;
    mask.onclick = hide;

    // 添加学生
    form.onsubmit = function (e) {
        // 禁止默认提交
        e.preventDefault();
        let data = new FormData(this);
        if (data.get('stu_name').trim() == '') return alert('填写姓名');
        let action = this.dataset.action;
        // 添加
        if (action == 'add') {
            axios({
                url: `http://127.0.0.1:8080/api/user/create`,
                method: 'post',
                data: {
                    stu_name: data.get('stu_name'),
                    stu_age: data.get('stu_age'),
                    stu_sex: data.get('stu_sex')
                }
            }).then(res => {
                let { data } = res;
                if (data.status) return alert(data.msg);
                alert(data.msg);
                close.click();
                // 重新渲染
                init();
            });
        }
        // 编辑更新
        if (action == 'update') {
            let id = this.dataset.id;
            axios({
                url: `http://127.0.0.1:8080/api/user/edit/${id}/update`,
                method: 'put',
                data: {
                    stu_id: id,
                    stu_name: data.get('stu_name'),
                    stu_age: data.get('stu_age'),
                    stu_sex: data.get('stu_sex')
                }
            }).then(res => {
                let { data } = res;
                if (data.status) return alert(data.msg);
                alert(data.msg);
                close.click();
                // 重新渲染
                init({ page, search });
            });
        }
    }

    // 改变全选
    const chkAll = document.querySelector('#chkAll');
    chkAll.onclick = function () {
        tbody.querySelectorAll('.chk').forEach(el => el.checked = this.checked);
    };

    // 批量软删
    delAll.onclick = function () {
        let ids = [];
        tbody.querySelectorAll('.chk').forEach(el => el.checked && ids.push(el.dataset.id));
        axios({
            url: `http://127.0.0.1:8080/api/user/delete`,
            method: 'delete',
            data: ids
        }).then(res => {
            let { data } = res;
            if (data.status) return alert(data.msg);
            alert(data.msg);
            // 重新渲染
            init({ page, search });
        });
    }

    // 事件监听
    tbody.addEventListener('click', e => {
        // checkbox事件
        if (e.target.nodeName === 'INPUT' && e.target.type === 'checkbox' && e.target.className === 'chk') {
            chkAll.checked = [...tbody.querySelectorAll('.chk')].every(el => el.checked);
        }

        // a标签事件
        if (e.target.nodeName === 'A') {
            // 编辑
            if (e.target.dataset.action === 'edit') {
                let id = e.target.dataset.id;
                form.querySelector('h3').innerHTML = '编辑';
                axios({
                    url: `http://127.0.0.1:8080/api/user/edit/${id}`,
                    method: 'get',
                }).then(res => {
                    let { data } = res;
                    if (data.status) return alert(data.msg);
                    // 渲染表单
                    form.stu_name.value = data.data[0].stu_name;
                    form.stu_age.value = data.data[0].stu_age;
                    form.stu_sex.value = data.data[0].stu_sex;
                    form.dataset.action = 'update';
                    form.dataset.id = id;
                    show();
                });
            }

            // 软删除
            if (e.target.dataset.action === 'del') {
                let id = e.target.dataset.id;
                axios({
                    url: `http://127.0.0.1:8080/api/user/delete/${id}`,
                    method: 'delete',
                }).then(res => {
                    let { data } = res;
                    if (data.status) return alert(data.msg);
                    alert(data.msg);
                    // 重新渲染
                    init({ page, search });
                });
            }

            // 还原
            if (e.target.dataset.action === 'restore') {
                let id = e.target.dataset.id;
                axios({
                    url: `http://127.0.0.1:8080/api/user/patch/${id}`,
                    method: 'patch',
                }).then(res => {
                    let { data } = res;
                    if (data.status) return alert(data.msg);
                    alert(data.msg);
                    // 重新渲染
                    init({ page, search });
                });
            }
        }
    });
</script>

</html>